﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LorraineSec.Libraries.Sensors
{
    /// <summary>
    /// This is the root class that all sensor types must inherit from
    /// and implement. The methods, fields and delegates provided here
    /// should be universal to all inheritors of this class.
    /// </summary>
    public class Sensor
    {
        #region Constants
        public const string TYPE_DELIMETER = ";";
        public const string TYPE_ATTACH = TYPE_DELIMETER + "ATTACH:";
        public const string TYPE_DETACH = TYPE_DELIMETER + "DETACH.";
        public const string TYPE_ERROR = TYPE_DELIMETER + "ERROR:";

        public const char SPLIT_CHAR = ',';
        #endregion

        #region SensorType Static Library Functions
        public static Dictionary<SensorType,uint> SensorTypeIDMap = new Dictionary<SensorType,uint>();
        public static Dictionary<uint, SensorType> SensorIDTypeMap = new Dictionary<uint, SensorType>();
        public static void InitDevLibTypes()
        {
            if (SensorTypeIDMap.Count == 0)
            {
                AddDevLibType(typeof(PhidgetIR_Lib), (uint)SensorTypeIDMap.Count + 1);
                AddDevLibType(typeof(PhidgetUSBRFID_Lib), (uint)SensorIDTypeMap.Count + 1);
            }
        }
        private static void AddDevLibType(Type t, uint id)
        {
            SensorIDTypeMap.Add(id, t);
            SensorTypeIDMap.Add(t, id);
        }
        public class SensorType : IComparable<SensorType>
        {
            private Type theType;

            private SensorType(Type t) { theType = t; }
            public static implicit operator SensorType(Type t)
            {
                return new SensorType(t);
            }
            public static explicit operator Type(SensorType t)
            {
                return t.theType;
            }
            public override bool Equals(object obj)
            {
                if(obj is SensorType)
                    return (CompareTo((SensorType)obj) == 0);
                return base.Equals(obj);
            }
            public override int GetHashCode()
            {
                return theType.GetHashCode();
            }          
            public override string ToString()
            {
                return theType.Name;
            }
            public int CompareTo(SensorType other)
            {
                if (theType.IsEquivalentTo(other.theType))
                    return 0;
                return 1;
            }
        }
        #endregion

        /// <summary>
        /// The delegate required for subscribing to updates from the sensor.
        /// </summary>
        /// <param name="frame">A frame which holds data returned from the sensor.</param>
        public delegate void SensorRecv(SensorFrame frame);

        protected List<SensorRecv> subscribers;

        public Sensor()
        {
            subscribers = new List<SensorRecv>();
        }

        /// <summary>
        /// Initialize communication with the sensor hardware.
        /// </summary>
        /// <returns>True if successful. False if unsuccessful.</returns>
        public virtual bool initiate() { return false; }
        /// <summary>
        /// Shutdown communication with the sensor hardware.
        /// </summary>
        /// <returns>True if successful. False if unsuccessful.</returns>
        public virtual bool shutdown() { return false; }

        /// <summary>
        /// Adds the given delegate to the subscription list.
        /// </summary>
        /// <param name="call">The delegate of the function to receive callbacks.</param>
        public void subscribe(SensorRecv call)
        {
            if(call != null)
                lock (subscribers)
                {
                    subscribers.Add(call);
                }
        }

        /// <summary>
        /// Remove the given delegate from the subscribers list.
        /// </summary>
        /// <param name="call">The delegate of the function to stop receiving callbacks.</param>
        /// <returns>True if successful. False if unsuccessful.</returns>
        public bool unsubscribe(SensorRecv call)
        {
            lock (subscribers)
            {
                return subscribers.Remove(call);
            }
        }

        /// <summary>
        /// Performs callbacks to all of the subcribers
        /// and passes the given frame as a parameter.
        /// </summary>
        /// <param name="frame">The data frame to pass from the sensor to the subscribers.</param>
        protected void notify(SensorFrame frame)
        {
            //Lock for thread-safeness
            lock(subscribers)
            {
                //Loop through each subscriber
                foreach (SensorRecv recv in subscribers)
                {
                    //Perform an asynchronus invoke to the subscriber
                    recv.BeginInvoke(frame, null, null);
                }
            }
        }
    }
}
